package string;

import java.util.*;

/**
 * 22.括号生成
 给出 n 代表生成括号的对数，请你写出一个函数，使其能够生成所有可能的并且有效的括号组合。

 例如，给出 n = 3，生成结果为：

 [
 "((()))",
 "(()())",
 "(())()",
 "()(())",
 "()()()"
 ]

 来源：力扣（LeetCode）
 链接：https://leetcode-cn.com/problems/generate-parentheses
 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。

 变形？{[()]}
 */
public class Q22_GenerateParenthesis {
    // 1.官方题解 枚举，递归全排列
    public static void main(String[] args) {
        new Q22_GenerateParenthesis().generateParenthesis(2);
        new Q22_GenerateParenthesis().generateParenthesisCore(2);
    }

    public List<String> generateParenthesis(int n) {
        List<String> combinations = new ArrayList();
        generateAll(new char[2 * n], 0, combinations);
        return combinations;
    }

    public void generateAll(char[] current, int pos, List<String> result) {
        if (pos == current.length) {
            if (valid(current))
                result.add(new String(current));
        } else {
            // 组合
            current[pos] = '(';
            generateAll(current, pos+1, result);
            current[pos] = ')';
            generateAll(current, pos+1, result);
        }
    }

    public boolean valid(char[] current) {
        int balance = 0;
        for (char c: current) {
            if (c == '(') balance++;
            else balance--;
            if (balance < 0) return false;
        }
        return (balance == 0);
    }

    // 2.官方题解 递归回溯
    public List<String> generateParenthesisCore(int n) {
        List<String> ans = new ArrayList();
        backtrack(ans, "", 0, 0, n);
        return ans;
    }

    public void backtrack(List<String> ans, String cur, int open, int close, int max){
        if (cur.length() == max * 2) {
            ans.add(cur);
            return;
        }
        if (open < max)
            backtrack(ans, cur+"(", open+1, close, max);
        if (close < open)
            backtrack(ans, cur+")", open, close+1, max);
    }
    /**
     * 一是列出所有情况
     * 二是直接找出结果，回退为了找到下一个满足条件的结果（不知道怎么表述）
     * ( ( ) )
     *   ) ( )
     */

    // 3.闭合数
    private List<String> generateParenthesisClosed(int n) {
        List<String> ans = new ArrayList();
        if (n == 0) {
            ans.add("");
        } else {
            for (int c = 0; c < n; ++c)
                for (String left: generateParenthesisClosed(c))
                    for (String right: generateParenthesisClosed(n-1-c))
                        ans.add("(" + left + ")" + right);
        }
        return ans;
    }

}